

class BasicOptimize(object):
    def __init__(self):
        self.num_assets = 0
        self.boundaries = ()
        self.instrument_type_constraints = {}  # {"股票":(1,0), "债券": (1,0), "货币": (1,0), "海外":(1,0), "商品":(1,0)}
        self.instrument_type_list = []

    def set_contraints(self):
        # cons = ({'type': 'eq', 'fun': total_weight_constraint},
        #         {'type': 'ineq', 'fun': long_only_constraint},
        # # {'type': 'eq', 'fun': lambda w: w[0] - 0.2},  # 活期
        pass

    def set_symbol_constraints(self, symbol_weight_list=[]):
        self.boundaries = symbol_weight_list

    def set_instrument_type_constraints(self, weight_by_instrument_type={}, instrument_type_list=[]):
        self.instrument_type_constraints = weight_by_instrument_type
        self.instrument_type_list = instrument_type_list

    def _process_symbol_constraints(self):
        num_assets = self.num_assets
        if len(self.boundaries) == 0:
            bnds = tuple((0, 1) for x in range(num_assets))  # 默认权重
        else:
            bnds = self.boundaries
        # print("Symbol Weights")
        # print(self.boundaries)
        return bnds

    def _process_instrument_type_constraints(self):
        cons = []
        for instrument_type, target_weight_range in self.instrument_type_constraints.items():
            max_weight = target_weight_range[1]
            min_weight = target_weight_range[0]
            #
            if max_weight < 1:
                cons.append({'type': 'ineq',
                             'fun': Calc_Weight_by_Instrument_Type,
                             'args': (self.instrument_type_list, instrument_type, max_weight, "Max")})
            #
            if min_weight > 0:
                print(instrument_type)
                cons.append({'type': 'ineq',
                             'fun': Calc_Weight_by_Instrument_Type,
                             'args': (self.instrument_type_list, instrument_type, min_weight, "Min")})
        #
        return cons

    def _process_constraints(self):
        bnds = self._process_symbol_constraints()
        instrument_type_cons = self._process_instrument_type_constraints()
        # self.constraints = [{'type': 'eq', 'fun': lambda x: np.sum(x) - 1}]
        return bnds, instrument_type_cons

    def optimize(self):
        pass


def Calc_Asset_Type_Weights(weights, asset_type_list):
    asset_type_weights = {}
    num_assets = len(weights)
    for i in range(num_assets):
        # 循环资产的权重和类型
        weight = weights[i]
        asset_type = asset_type_list[i]
        #
        if asset_type not in asset_type_weights.keys():
            asset_type_weights[asset_type] = 0
        #
        asset_type_weights[asset_type] += weight
    #
    return asset_type_weights


def Calc_Weight_by_Instrument_Type(weights, instrument_type_list, target_instrument_type, target_weight, min_max):
    asset_type_weights = {}
    num_assets = len(weights)
    total_weights = 0
    for i in range(num_assets):
        # 循环资产的权重和类型
        weight = weights[i]
        asset_type = instrument_type_list[i]
        #
        if asset_type == target_instrument_type:
            total_weights += weight
    #
    if min_max == "Max":
        return target_weight - total_weights
    elif min_max == "Min":
        return total_weights - target_weight